// apply() 方法与 call() 方法类似，区别在于 apply() 方法在接收调用函数参数的
// 时候是以数组的形式接收的，所以在对参数的处理时会有所不同。
// bind() 方法创建一个新的函数
let count = 0;
let obj = {
  count:1
}

function addNum(arg1,arg2){
    return this.count + arg1 + arg2;
}

Function.prototype.myCall = function (context) {
    if (typeof this !== 'function') throw new TypeError('Error');

    context = context || window
    context.fn = this
    const args = [...arguments].slice(1)
    const result = context.fn(...args)
    delete context.fn

    return result
}

console.log(addNum.myCall(obj,2,3)) // 6

Function.prototype.myApply = function (context) {
    if (typeof this !== 'function') throw new TypeError('Error');
    
    context = context || window
    context.fn = this
    let result
    if (arguments[1]) {
      result = context.fn(...arguments[1])
    } else {
      result = context.fn()
    }
    delete context.fn
  
    return result
  }

  Function.prototype.myBind = function (context) {
    if (typeof this !== 'function') throw new TypeError('Error');
  
    const _this = this
    const args = [...arguments].slice(1)
  
    return function F() {
      if (this instanceof F) {   //  通过 new 方式调用的情况
        return new _this(...args, ...arguments)
      }
      return _this.apply(context, args.concat(...arguments))
    }
  }
